package com.zyw.security.shiro.web.filter;

import com.zyw.security.shiro.LoginFrom;
import com.zyw.security.shiro.web.authc.tk.FormAuthcToken;
import com.zyw.security.shiro.web.authc.tk.SmsAuthcToken;
import com.zyw.security.shiro.web.authc.tk.WeixinQYAuthcToken;
import com.zyw.security.shiro.web.authc.tk.factory.ShiroAuthcTokenFactory;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 登录认证拦截器
 *
 * @author zhangyw
 * @date 2018/1/5 16:14
 */
public class UserLoginAuthenticationFilter extends BasicAuthenticationFilter {

    // 接口认证url
    private String loginAuthUrl;

    public String getLoginAuthUrl() {
        return loginAuthUrl;
    }

    public void setLoginAuthUrl(String loginAuthUrl) {
        this.loginAuthUrl = loginAuthUrl;
    }

    private ShiroAuthcTokenFactory shiroAuthcTokenFactory;

    public void setShiroAuthcTokenFactory(ShiroAuthcTokenFactory shiroAuthcTokenFactory) {
        this.shiroAuthcTokenFactory = shiroAuthcTokenFactory;
    }

    /**
     * 判断是否登录认证url
     *
     * @param request  req
     * @param response res
     * @return true false
     */
    public boolean isLoginAuthUrl(ServletRequest request, ServletResponse response) {
        return pathsMatch(getLoginAuthUrl(), request);
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        if (isLoginAuthUrl(request, response)) {
            if (log.isTraceEnabled()) {
                log.trace("Login submission detected.  Attempting to execute login.");
            }
            return executeLogin(request, response);
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Attempting to access a path which requires authentication.  Forwarding to the " +
                        "Authentication url [" + getLoginUrl() + "]");
            }

            saveRequestAndRedirectToLogin(request, response);
            return false;
        }
    }

    private boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
        AuthenticationToken token = shiroAuthcTokenFactory.createToken(request, response);
        if (token == null) {
            String msg = "createToken method implementation returned null. A valid non-null AuthenticationToken " +
                    "must be created in order to execute a login attempt.";
            throw new IllegalStateException(msg);
        }
        try {
            Subject subject = getSubject(request, response);
            subject.login(token);
            return onLoginSuccess(token, subject, request, response);
        } catch (AuthenticationException e) {
            return onLoginFailure(token, e, request, response);
        }
    }

    private boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {

        // 如果是 微信企业扫码登录，认证通过后，根据用户状态跳转指定页面
        // 新用户[即平台用户表中不存在当前用户],跳转至补充填写用户信息界面
        // 老用户[即平台用户表中存在当前用户],跳转至欢迎页面或者redirect页面
        if (token instanceof WeixinQYAuthcToken) {
            // 管理系统不用考虑新用户，直接跳转至欢迎页面或者redirect页面
            saveRequestAndRedirectToSuccess(request, response);
            return false;
        }

        // 其它情况继续执行 login 流程

        return true;
    }

    private boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        if (log.isDebugEnabled()) {
            log.debug("Authentication exception", e);
        }
        request.setAttribute(LOGIN_ERROR_KEY_ATTRIBUTE_NAME, e.getMessage());
        //login failed, let request continue back to the login page:
        return true;
    }
}
